﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rhino.Mocks;
using Rhino.Mocks.Impl;
using System.Diagnostics;

namespace Rhino.AutoMocker
{
    public class AutoMocker : IDisposable
    {
        private bool isDebugEnabled = true;

        public bool IsDebugEnabled
        {
            get { return isDebugEnabled; }
            set { isDebugEnabled = value; }
        }

        public T Create<T>()
        {
            Type targetType = typeof(T);
            T instance = Activator.CreateInstance<T>();
            MockDependecies<T>(ref instance);
            return instance;
        }

        public T CreatePartial<T>()
        {
            Type targetType = typeof(T);
            T instance = MockRepository.GeneratePartialMock<T>();
            MockDependecies<T>(ref instance);
            return instance;
        }

        public void MockDependecies<T>(ref T t)
        {
            foreach (var property in t.GetType().GetProperties())
            {
                if ((property.PropertyType.IsAbstract ||
                    property.PropertyType.IsClass ||
                    property.PropertyType.IsGenericType ||
                    property.PropertyType.IsInterface) &&
                    property.PropertyType.IsPublic &&
                    !property.PropertyType.Namespace.StartsWith("System.")) // Don't stub the Microsoft's public properties / members.
                {
                    try
                    {
                        if (components.ContainsKey(property.PropertyType))
                        {
                            property.SetValue(t, components[property.PropertyType], null);
                        }
                        else
                        {
                            var mock = MockRepository.GenerateStub(property.PropertyType);
                            property.SetValue(t, mock, null);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (IsDebugEnabled)
                        {
                            Debug.WriteLine(ex.Message);
                            Debug.WriteLine(string.Format("Unable create mock object for {0}", property.PropertyType));
                        }
                    }
                }
            }
        }

        public void AddComponent<T>(object instance)
        {
            components[typeof(T)] = instance;
        }

        private IDictionary<Type, Object> components = new Dictionary<Type, Object>();

        #region IDisposable Members

        public void Dispose()
        {
            components = null;
        }

        #endregion
    }


}
